/**
 *  Serponix is an arcade game in focus to multiplayer based on the classic game Snake.
 *  Copyright (C) 2010 - 2011  Daniel Vala
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License,
 *  or  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.

 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  If you have any question do not hesitate to contact author
 *  on e-mail address: danielvala42@gmail.com
 */
package com.serponix.gui.lobby;

import com.serponix.gui.MainPanel;
import com.serponix.settings.SettingsFactory;
import com.serponix.game.Player;
import com.serponix.game.Mapa;
import java.net.DatagramPacket;
import java.util.ArrayList;
import java.util.List;
import com.serponix.net.Informace;
import com.serponix.net.Server;
import com.serponix.net.UDPServer;

/**
 * Model lobby pro server rozšiřuje model
 * o parametry a metody specifické pro server.
 * @author Daniel Vala
 */
public class ModelLobbyServer extends ModelLobby {

    private Server server;
    // Hráči, které je možno vybrat do hry
    private List<Player> hraci;
    // Aktuálne vybraní hráči do hry, starají se o ně modelyComboBoxů
    private List<Player> vybraniHraci;
    private List<ModelComboBoxHrace> modelyComboBoxuHracu;
    private Mapa mapa;

    public ModelLobbyServer(MainPanel okno) {
        super(okno);
        server = new UDPServer(this);
        setNet(server);
        mapa = new Mapa();
        hraci = new ArrayList<Player>();
        vybraniHraci = new ArrayList<Player>();
        modelyComboBoxuHracu = new ArrayList<ModelComboBoxHrace>();

        Player.Control[] ovladani = {Player.Control.KEYBOARD1, Player.Control.KEYBOARD2, Player.Control.KEYBOARD3, Player.Control.KEYBOARD4};
        for (int i = 0; i < SettingsFactory.getNastaveniHry().getPocetHracu(); i++) {
            hraci.add(new Player(getJmenoHrace(i), ovladani[i], null));
        }

        setMod(SettingsFactory.getNastaveniHry().getMod());
        setRychlostHry(SettingsFactory.getNastaveniHry().getRychlost());
        setNazevMapy("prázdná mapa");

        new Thread(server).start();
    }

    public void vyhodHrace(int cisloComboBoxu) {
        Player hrac = getModelyComboBoxuHracu().get(cisloComboBoxu).getPredchoziHrac();
        server.posliDataKlientovi(Informace.VYHODIT + Informace.ODDELOVAC1, hrac.getPacket());
        hraci.remove(hrac);
        getModelyComboBoxuHracu().get(cisloComboBoxu).setSelectedItem("OTEVŘENO");
    }

    public void odstranHrace(Player hrac) {
        hraci.remove(hrac);
        for (int i = 0; i < getModelyComboBoxuHracu().size(); i++) {
            if (getModelyComboBoxuHracu().get(i).getSelectedItem().equals(hrac)) {
                getModelyComboBoxuHracu().get(i).setSelectedItem("OTEVŘENO");
                getModelyComboBoxuHracu().get(i).vyberChaged();
            }
        }
    }

    public Server getServer() {
        return server;
    }

    public Mapa getMapa() {
        return mapa;
    }

    public List<ModelComboBoxHrace> getModelyComboBoxuHracu() {
        return modelyComboBoxuHracu;
    }

    /**
     * Vrátí seznam všech hráčů.
     * @return Seznam všech hráčů.
     */
    public List<Player> getHraci() {
        return hraci;
    }

    /**
     * Vrátí seznam hráčů, kteří jsou již vybrání v některém z comboBoxů.
     * @return Seznam hráčů.
     */
    public List<Player> getVybraniHraci() {
        return vybraniHraci;
    }

    public boolean isAIPlaying() {
        for (int i = 0; i < vybraniHraci.size(); i++) {
            if (vybraniHraci.get(i).getOvladani() == Player.Control.AI_STANDARD) {
                return true;
            }
        }
        return false;
    }

    public boolean isClientPlaying() {
        for (int i = 0; i < vybraniHraci.size(); i++) {
            if (vybraniHraci.get(i).getOvladani() == Player.Control.CLIENT) {
                return true;
            }
        }
        return false;
    }

    /**
     * Přidá nového hráče a zobrazí ho na volné pozici, pokud existuje.
     * @param hrac Nový hráč.
     */
    public boolean addHrac(Player hrac) {
        boolean uspech = zobrazHraceNaVolnePozici(hrac);
        if (uspech) {
            hraci.add(hrac);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Zobrazí daného hráče na první pozici OTEVŘENO, pokud existuje.
     * @param hrac Hráč k zobrazení.
     * @return true, pokud pro hráče byla volná pozice. Jinak false.
     */
    private boolean zobrazHraceNaVolnePozici(Player hrac) {
        for (int i = 0; i < modelyComboBoxuHracu.size(); i++) {
            if (modelyComboBoxuHracu.get(i).getSelectedItem().equals("OTEVŘENO")) {
                modelyComboBoxuHracu.get(i).setSelectedItem(hrac);
                modelyComboBoxuHracu.get(i).vyberChaged();
                return true;
            }
        }
        return false;
    }

    /**
     * Pošle klientům stavy výběru všech comboBoxů hráčů.
     */
    public void posliStavyComboBoxu() {
        for (int i = 0; i < modelyComboBoxuHracu.size(); i++) {
            modelyComboBoxuHracu.get(i).posliStav();
        }
    }

    public void posliMod() {
        server.poslatData(Informace.MOD_HRY + Informace.ODDELOVAC1 + getMod());
    }

    public void posliStavRychlosti() {
        server.poslatData(Informace.RYCHLOST + Informace.ODDELOVAC1 + getRychlostHry());
    }

    public void posliVsechnyInformace() {
        posliStavRychlosti();
        posliMod();
        posliStavyComboBoxu();
    }

    public void posliVsechnyInformace(DatagramPacket packet) {
        server.posliDataKlientovi(Informace.RYCHLOST + Informace.ODDELOVAC1 + getRychlostHry(), packet);
        server.posliDataKlientovi(Informace.MOD_HRY + Informace.ODDELOVAC1 + getMod(), packet);
        server.posliDataKlientovi(Informace.NAZEV_MAPY + Informace.ODDELOVAC1 + getMapa().getNazev(), packet);
        for (int i = 0; i < modelyComboBoxuHracu.size(); i++) {
            modelyComboBoxuHracu.get(i).posliStavKlientovi(packet);
        }
    }

    /**
     * Vytvoří nový modelComboBoxHrace, přidá ho do seznamu a vrátí ho.
     * @param cislo Číslo daného comboBoxu, tj. kolik už jich je vytvořeno + 1.
     * @return Nově vytvořený comboBoxModel.
     */
    public ModelComboBoxHrace createAndReturnModelComboBoxHrace(int cislo) {
        ModelComboBoxHrace retval = new ModelComboBoxHrace(this, cislo, server);
        modelyComboBoxuHracu.add(retval);
        return retval;
    }

    /**
     * Nastaví danou rychlost hry a pošle nastavení všem klientům.
     * @param rychlostHry Nová rychlost hry.
     */
    public void setRychlostHryAPosliKlientum(int rychlostHry) {
        setRychlostHry(rychlostHry);
        server.poslatData(Informace.RYCHLOST + Informace.ODDELOVAC1 + rychlostHry);
    }

    public void setMapa(Mapa mapa) {
        setNazevMapy(mapa.getNazev());
        this.mapa = mapa;
        getServer().poslatData(Informace.NAZEV_MAPY + Informace.ODDELOVAC1 + getMapa().getNazev());
    }

    /**
     * Nastaví daný mód hry a pošle nastavení všem klientům.
     * @param mod Nový mód.
     */
    public void setModHry(String mod) {
        setMod(mod);
        posliMod();
    }
}
